package cn.qzbook.redisData;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.redis.connection.RedisZSetCommands;
import org.springframework.data.redis.core.DefaultTypedTuple;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

/**
 * @Description
 * @Author zc
 * @Date 2020/11/10 上午1:13
 *
 *
 * spring操作zset的时候，RedisTemplate的配置需要在key序列化和value序列化上进行配置
 *          <property name="keySerializer" ref="stringRedisSerializer"/>
 *          <property name="valueSerializer" ref="stringRedisSerializer"/>
 */
public class RedisZSet {


    public static void main(String[] args) {

        testZSet();
    }

    public static void testZSet(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:application.xml");
        RedisTemplate redisTemplate = applicationContext.getBean(RedisTemplate.class);

        //Spring提供的TypedTuple来操作有序集合
        Set<ZSetOperations.TypedTuple> set1 = new HashSet<>();
        Set<ZSetOperations.TypedTuple> set2 = new HashSet<>();

        int j = 9;
        for (int i = 1; i <= 9; i++){
            j--;
            //计算分数和值
            Double score1 = Double.valueOf(1);
            String value1 = "x"+i;

            Double score2 = Double.valueOf(j);
            String value2 = j % 2== 1 ? "y"+j : "x"+j;
            //使用spring提供的默认TypedTuple---DefaultTypedTuple
            ZSetOperations.TypedTuple typedTuple1 = new DefaultTypedTuple(value1,score1);
            set1.add(typedTuple1);
            ZSetOperations.TypedTuple typedTuple2 = new DefaultTypedTuple(value2,score2);
            set2.add(typedTuple2);
        }
        //将元素插入有序集合zset1
        redisTemplate.opsForZSet().add("zset1",set1);
        redisTemplate.opsForZSet().add("zset2",set2);

        //统计总数
        Long size = null;
        size = redisTemplate.opsForZSet().zCard("zset1");
        System.out.println(size);

        //计分数为score，name下面的方法就是求 3<=score<=6的元素
        Long count = size = redisTemplate.opsForZSet().count("zset1", 3, 6);

        //从下标一开始截取五个元素，但是不返回分数，每一个元素是string
        Set set = null;
        set = redisTemplate.opsForZSet().range("zset",1,5);
        printSet(set);

        //截取集合中所有元素，并且对象按分数排序，并返回分数，每一个元素是TypedTuple
        set = redisTemplate.opsForZSet().rangeWithScores("zset1",0,-1);
        printTypedTuple(set);

        //将zset1和zset2两个集合的交集放入集合inter_zset
        size = redisTemplate.opsForZSet().intersectAndStore("zset1","zset2","inter_zset");

        //区间
        RedisZSetCommands.Range range = RedisZSetCommands.Range.range();
        range.lt("x8");//小于
        range.gt("x1");//大于
        set = redisTemplate.opsForZSet().rangeByLex("zset1",range);
        printSet(set);
        //限制返回个数
        RedisZSetCommands.Limit limit = RedisZSetCommands.Limit.limit();
        //限制返回个数
        limit.count(4);
        //限制从第5个开始截取
        limit.offset(5);
        //求区间内的的元素，并限制返回4条
        set = redisTemplate.opsForZSet().rangeByLex("zset1",range,limit);


        //求排行，排名第1返回0，第2返回1
        Long rank = redisTemplate.opsForZSet().rank("zset1","x4");
        System.out.println("rank="+rank);

        //删除元素返回个数
        size = redisTemplate.opsForZSet().remove("zset1","x5","x6");
        System.err.println("delete="+size);

        //按照排行删除从0开始算起，这里将删除排名第2和第3的元素
        redisTemplate.opsForZSet().removeRange("zset1",1,2);

        //获取所有的集合元素和分数，以-1代表全部元素
        set = redisTemplate.opsForZSet().rangeWithScores("zset2",0,-1);
        printTypedTuple(set);

        //删除指定元素
        size = redisTemplate.opsForZSet().remove("zset2","y5","y3");
        System.err.println(size);

        //给集合中的一个元素的分加上11
        Double db1 = redisTemplate.opsForZSet().incrementScore("zset1","x1",11);
        System.out.println(db1);

        redisTemplate.opsForZSet().removeRangeByScore("zset",1,2);
        set = redisTemplate.opsForZSet().reverseRangeWithScores("zset2",1,10);
        printTypedTuple(set);
    }

    /**
     *  打印TypedTuple集合
     * @param set
     * */
    public static void printTypedTuple(Set<ZSetOperations.TypedTuple> set){
        if (set == null || set.isEmpty()) {
            return;
        }

        Iterator iterator = set.iterator();
        while (iterator.hasNext()){
            ZSetOperations.TypedTuple val = (ZSetOperations.TypedTuple) iterator.next();
            System.out.println("{value="+val.getValue()+".score="+val.getScore()+"}\n");
        }
    }

    /**
     * 打印普通集合
     * */
    public static  void printSet(Set set){
        if (set == null || set.isEmpty()){
            return;
        }
        Iterator iterator = set.iterator();
        while (iterator.hasNext()){
            Object val = iterator.next();
            System.out.println(val+"\t");
        }
        System.out.println();
    }

}
